package com.data.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.data.pojo.AnnualProfit;
import com.data.pojo.Profit;
import com.data.pojo.StockData;
import com.data.pojo.Trade;
import com.data.service.StockDataService;
import com.data.util.CommonUtil;
import com.data.util.Result;
import com.data.util.ResultEnum;
import org.aspectj.weaver.ast.Var;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * @Author Str
 * @Date 2022/1/25 13:34
 * @Description :
 */
@RestController
@CrossOrigin  // 解决跨域问题
@RequestMapping("/stockData")
public class StockDataController {

    @Autowired
    private StockDataService stockDataService;


    /**
     * 提交一个新的股票数据到redis，自定义时间区间
     * localhost:8000/stockData/putStockData?code=0600000&startTime=20190101&endTime=20220101
     */
    @RequestMapping("/putStockData")
    public List<StockData> putStockData(String code, String startTime, String endTime) {
        return stockDataService.putStockData(code, startTime, endTime);
    }

    /**
     * 提交一个新的股票数据到redis，当前时间到过去5年的数据
     * localhost:8000/stockData/pullStockData/0600000
     */
    @GetMapping("/pullStockData/{stockCode}")
    public Result pullStockData(@PathVariable("stockCode") String stockCode) {
        if (stockCode == null || stockCode.equals("")) {
            return new Result(ResultEnum.PARAMS_IS_BLANK);
        }
        if (!CommonUtil.isNumber(stockCode) || stockCode.length() != 7) {
            return new Result(ResultEnum.PARAM_IS_INVALID);
        }
        List<StockData> stockDataList = null;
        try {
            stockDataList = stockDataService.putStockData(stockCode, CommonUtil.getLastDate(5), CommonUtil.getNowDate());
            if (stockDataList != null && stockDataList.size() != 0) {
                return new Result(ResultEnum.SUCCESS);
            }
        } catch (Exception e) {
            return new Result(ResultEnum.PARAMS_IS_ERROR);
        }
        return new Result(ResultEnum.ERROR);
    }

    /**
     * 获取股票数据，从redis中
     * localhost:8000/stockData/getStockData/0600000
     */
    @GetMapping("/getStockData/{stockCode}")
    public List<StockData> getStockData(@PathVariable String stockCode) {
        return stockDataService.getStockData(stockCode);
    }

    /**
     * 获取指定日期区间的股票数据
     * localhost:8000/stockData/obtainStockData/0000001/20210901/20210910
     * localhost:8000/stockData/obtainStockData?stockCode=0000001&strStartDate=20210901&strEndDate=20210910
     *
     * @param stockCode     股票代码
     * @param ma            均线
     * @param buyThreshold  买入阈值
     * @param sellThreshold 卖出阈值
     * @param serviceCharge 手续费
     * @param strStartDate  开始日期
     * @param strEndDate    结束日期
     * @return java.util.List<com.data.pojo.StockData>
     */
    @GetMapping("/obtainStockData/{stockCode}/{ma}/{buyThreshold}/{sellThreshold}/{serviceCharge}/{startDate}/{endDate}")
//    @RequestMapping("/obtainStockData")
    public Map<String, Object> obtainStockData(
            @PathVariable("stockCode") String stockCode,
            @PathVariable("ma") int ma,
            @PathVariable("buyThreshold") float buyThreshold,
            @PathVariable("sellThreshold") float sellThreshold,
            @PathVariable("serviceCharge") float serviceCharge,
            @PathVariable("startDate") String strStartDate,
            @PathVariable("endDate") String strEndDate) {
//    public Map<String, Object> obtainStockData(String stockCode, String strStartDate, String strEndDate) {
        System.out.println("strStartDate:" + strStartDate);
        System.out.println("strEndDate:" + strEndDate);
        // 这里会出现类型转换异常 java.util.LinkedHashMap cannot be cast to com.data.pojo.StockData
        List<StockData> allStockData = (List<StockData>) stockDataService.getStockData(stockCode);
        // 将map转成json，再反序列化成对象
        ObjectMapper mapper = new ObjectMapper();
        List<StockData> list = mapper.convertValue(allStockData, new TypeReference<List<StockData>>() {
        });
        // **由于存入数据的的顺序和在代码中的数据使用逻辑不同，所以在这里将获取到的数据顺序反转**
        list = CollUtil.reverse(list);
        // 获取全部数据中的开始日期和结束日期 ==========
        String endDate = list.get(list.size() - 1).getDate();
        String startDate = list.get(0).getDate();

        // 获取指定日期区间的数据
        list = filterByDateRange(list, strStartDate, strEndDate);

        // 获取模拟结果
        Map<String, ?> simulateResult = stockDataService.simulate(ma, sellThreshold, buyThreshold, serviceCharge, list);
        List<Profit> profits = (List<Profit>) simulateResult.get("profits");  // 利润集合
        List<Trade> trades = (List<Trade>) simulateResult.get("trades");  // 交易记录集合

        // 计算指定日期区间的年数
        float years = stockDataService.getYear(list);
        // 计算股价变化
        float indexIncomeTotal = (list.get(list.size() - 1).getClosingPrice() - list.get(0).getClosingPrice()) / list.get(0).getClosingPrice();
        float indexIncomeAnnual = (float) Math.pow(1 + indexIncomeTotal, 1 / years) - 1;
        // 计算使用趋势投资后的股价变化
        float trendIncomeTotal = (profits.get(profits.size() - 1).getValue() - profits.get(0).getValue()) / profits.get(0).getValue();
        float trendIncomeAnnual = (float) Math.pow(1 + trendIncomeTotal, 1 / years) - 1;

        // 获取交易统计数据
        int winCount = (Integer) simulateResult.get("winCount");
        int lossCount = (Integer) simulateResult.get("lossCount");
        float avgWinRate = (Float) simulateResult.get("avgWinRate");
        float avgLossRate = (Float) simulateResult.get("avgLossRate");

        List<AnnualProfit> annualProfits = (List<AnnualProfit>) simulateResult.get("annualProfits");

        Integer recommendedLevel = (Integer) simulateResult.get("recommendedLevel");

        Map<String, Object> result = new HashMap<>();
        result.put("stockData", list);
        result.put("stockStartDate", startDate);
        result.put("stockEndDate", endDate);
        result.put("profits", profits);
        result.put("trades", trades);

        result.put("years", years);
        result.put("indexIncomeTotal", indexIncomeTotal);
        result.put("indexIncomeAnnual", indexIncomeAnnual);
        result.put("trendIncomeTotal", trendIncomeTotal);
        result.put("trendIncomeAnnual", trendIncomeAnnual);

        result.put("winCount", winCount);
        result.put("lossCount", lossCount);
        result.put("avgWinRate", avgWinRate);
        result.put("avgLossRate", avgLossRate);

        result.put("annualProfits", annualProfits);

        result.put("recommendedLevel", recommendedLevel);
        return result;
    }

    /**
     * 1. 当获取到指数数据后，要把对应的开始日期和结束日期拿到并显示在日期控件上
     * 2. 每次切换指数代码，都会更新开始日期和结束日期。
     * 3. 日期能够选择的范围在 开始日期 到 结束日期之间， 超过了就不能选择了。
     * 4. 当选择了新的日期范围的时候，会自动获取对应的数据出来。
     * 5. 对于服务端，如果没有提供开始和结束日期，则返回所有数据。 如果提供了，则返回指定日期范围的对应数据。
     * 6. 开始日期不能大于结束日期
     */
    private List<StockData> filterByDateRange(List<StockData> allStockData, String strStartDate, String strEndDate) {
        if (StrUtil.isBlankOrUndefined(strStartDate) || StrUtil.isBlankOrUndefined(strEndDate))
            return allStockData;

        List<StockData> result = new ArrayList<>();
        Date startDate = DateUtil.parse(strStartDate);
        Date endDate = DateUtil.parse(strEndDate);

        for (StockData data : allStockData) {
            Date date = DateUtil.parse(data.getDate());
            if (
                    date.getTime() >= startDate.getTime() && date.getTime() <= endDate.getTime()) {
                result.add(data);
            }
        }
        return result;
    }
}
